<template>
    <div class="file-upload">
        <h1>大文件分片上传、极速秒传</h1>
        <div class="file-upload-el">
 
            <el-upload
                    class="upload-demo"
                    drag
                    ref="upload"
                    :limit=1
                    :action="actionUrl"
                    :on-exceed="handleExceed"
                    :http-request="handUpLoad"
                    :auto-upload="false"
            >
                <i class="el-icon-upload"></i>
                <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
            </el-upload>
            <el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上传到服务器</el-button>
        </div>        
    </div>
</template>
 
<script>
    export default {
        name: "FileUpload",
        data() {
 
            return {
                actionUrl: 'http://127.0.0.1:18201/upload2',//上传的后台地址
                shardSize: 10 * 1024 * 1024, 
                uploadBegin:0,
                fileParam:{},
                checkInterval:null,
                shardData:[]
 
            };
        },
        methods: {
 
            handleExceed(files, fileList) {
                this.$message.warning(`当前限制选择 1个文件，本次选择了 ${files.length} 个文件，共选择了 ${files.length + fileList.length} 个文件`);
            },
            submitUpload() {
                this.$refs.upload.submit();
            },             
            async recursionUpload(param, file) {
                //FormData私有类对象，访问不到，可以通过get判断值是否传进去  
                let key = param.key;
                let shardIndex = param.shardIndex;
                let shardTotal = param.shardTotal;
                let shardSize = param.shardSize;
                let size = param.size;
                let fileName = param.fileName;
                let suffix = param.suffix; 
                let fileShard = this.getFileShard(shardIndex, shardSize, file); 
                //param.append("file", fileShard);//文件切分后的分片
                //param.file = fileShard;
                let totalParam = new FormData();
                totalParam.append('file', fileShard);
                totalParam.append("key", key);
                totalParam.append("shardIndex", shardIndex);
                totalParam.append("shardSize", shardSize);
                totalParam.append("shardTotal", shardTotal);
                totalParam.append("size", size);
                totalParam.append("fileName", fileName);
                totalParam.append("suffix", suffix);
                let config = {
                    //添加请求头
                    headers: {"Content-Type": "multipart/form-data"}
                }; 
                var res = await this.$http.post("/api/upload2/big-upload", totalParam, config)
 
                var resData = res.data;
                if (resData.success) {
                     this.shardData[shardIndex -1] = true;
                } else {
                    console.log("分片"+shardIndex+"上传失败")
                }
 
            },
 
            async handUpLoad(req) { 
                var file = req.file;
                /*  console.log('handUpLoad', req)
                  console.log(file);*/
                //let param = new FormData();
                //通过append向form对象添加数据
 
                //文件名称和格式，方便后台合并的时候知道要合成什么格式
                let fileName = file.name;
                let suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length).toLowerCase();
                
               
                // 文件分片
                // let shardSize = 10 * 1024 * 1024;    //以10MB为一个分片
                // let shardSize = 50 * 1024;    //以50KB为一个分片
                let shardSize = this.shardSize; 
                let size = file.size;
                let shardTotal = Math.ceil(size / shardSize); //总片数 
                // 生成文件标识，标识多次上传的是不是同一个文件
                let name = file.name;
                let idx = name.lastIndexOf(".");
                name = name.substring(0,idx);
                let key = new Date().getTime()+"_"+name;                
                this.shardData = [];
                this.uploadBegin = new Date().getTime(); 
                this.fileParam = {
                    shardSize: shardSize,
                    shardTotal: shardTotal,
                    key: key,
                    fileName: fileName,
                };
                for(var shardIndex=1;shardIndex<=shardTotal;shardIndex++){
                    this.shardData.push(false);
                    let param = {
                        key: key,
                        shardIndex: shardIndex,
                        shardSize: shardSize,
                        shardTotal: shardTotal,
                        size: size,
                        fileName: fileName,
                        suffix: suffix
                    }                    
                    this.recursionUpload(param,file);
                }    
              
                this.checkInterval = window.setInterval(this.checkComplete,1000);
            },
            async margeComplete(){
                let config = {
                    //添加请求头
                    headers: {"Content-Type": "application/json"}
                }; 
                console.log(this.fileParam); 
                var res = this.$http.post("/api/upload2/big-merge", this.fileParam, config) 
                var resData = res.data;
                if (resData.success) {
                    console.log("文件合并成功")
                } else {
                    console.log("文件合并失败")
                }
            },
            checkComplete(){
                var that = this;           
                var success = true;
                for(let idx = 0; idx < that.shardData.length; idx++) {
                    if(!that.shardData[idx]){
                        success = false;
                        break;
                    }                        
                }
                if(success){                   
                    console.log("上传完成,耗时："+(new Date().getTime() - this.uploadBegin));
                    this.margeComplete();
                    window.clearInterval(this.checkInterval);
                }
            },
 
            getFileShard(shardIndex, shardSize, file) { 
                let start = (shardIndex - 1) * shardSize;    //当前分片起始位置
                let end = Math.min(file.size, start + shardSize); //当前分片结束位置
                let fileShard = file.slice(start, end); //从文件中截取当前的分片数据
                return fileShard;
            },
 
 
        }
    }
 
</script>
 
<style>
    .v-box-card{
        width: 50%;
    }
</style>